<?php
/**
 * Определение ядра
 * 
 * Подключаем и определяем всё что использует ядро
 * @author Anton Zavidov
 * @package myLiveShop
 */
class Core extends Base {
	
	const LANG='LANG';
	const LANG_ID='LANG_ID';
	const MESSAGES='MESSAGES';
	const REFERER='REFERER';
	const FORM_ERRORS='FORM_ERRORS';
	const LAST_REQUEST='LAST_REQUEST';
	const LAST_ERROR='LAST_ERROR';
	/**
	 * Список предопределённых классов
	 *
	 * @var array
	 */
	private static $classes=array();
	/**
	 * Список переменных
	 *
	 * @var array
	 */
	private static $vars=array();
	/**
	 * Конструктор
	 *
	 */
	public function __construct(){
		parent::__construct(__CLASS__);
	}
	/**
	 * загружаем файлы по порядку
	 *
	 * @param array $list список подключаемых файлов
	 */
	public static function load($list){
		toArray($list);
		foreach ($list as $item) {
			//если в иимени в конце есть + значит не только подгружаем но и определяем
			if(strpos($item,"+")){
				$item=trim($item,"+");
				self::$classes[$item]=import($item,true);
			}else import($item);
		}
	}
	/**
	 * Проверяем подключен ли класс
	 *
	 * @param string $name
	 * @return boolean
	 */
	public static function checkClass($name){
		return isset(self::$classes[$name])?true:(self::findClass($name)?true:false);
	}
	/**
	 * Получаем класс из библиотеки по его имени
	 * 
	 * Если класс не найден то пытаемся его подгрузить
	 *
	 * @param string $name имя класса
	 * @return class
	 */
	public static function &getClass($name){
		global $imported;
		//если класс был раньше подшружен то берём из хранилища
		if(isset(self::$classes[$name]))return self::$classes[$name];
		else{
			//если находим то возвращаем
			if($found=self::findClass($name)){
				$return=($imported[$found]?$imported[$found]:import($found,true));
				return $return;
			//иначе возвращаем исключение
			}else{
				new CoreExeption('Не могу получить ссылку на класс '.$name,E_WARNING,__FILE__,__LINE__,array("name"=>$name));
				return false;
			}
		}
	}
	/**
	 * Ищем класс
	 * 
	 * пытыемся найти в хранилище так чтоб имя совпадало с путём
	 *
	 * @param string $name имя класса
	 * @return boolean
	 */
	private static function findClass($name){
		global $imported;
		//пытыемся найти в хранилище так чтоб имя совпадало с путём
		foreach ($imported as $item=>$key) {
			if($item==$name){
				return $item;
			}else{
				//делим путь по точке
				if(strpos($item,".")){
					$itemEx=explode(".",$item);
					if($itemEx[count($itemEx)-1]==$name){
						return $item;
					}
				}
			}
		}
		return false;
	}
	/**
	 * Сохраняем переменную
	 *
	 * @param mixed $name переменная либо массив ключь/значение
	 * @param mixed $value значение либо ничего если $name массив
	 */
	public static function set($name,$value=null){
		//если передан массив
		if(is_array($name)){
			foreach ($name as $key=>$item) {
				self::$vars[$key]=$item;
			}
		}
		//иначе записываем $value
		else self::$vars[$name]=$value;
	}
	/**
	 * Получаем переменную
	 *
	 * @param string $name имя переменной
	 * @return mixed значение
	 */
	public static function get($name){
		if(isset(self::$vars[$name]))return self::$vars[$name];
		return null;
	}
	//пользовательские функции
	
	/**
	 * получаем класс текущей базы
	 *
	 * @return DB
	 */
	public static function getDB(){
		if($type=Config::_("db_type")){
			return self::getClass($type);
		}
	}
	/**
	 * получаем класс сессий
	 *
	 * @return Session
	 */
	public static function getSession(){
		if($type=Config::_("session_type")){
			return self::getClass($type);
		}
	}
	/**
	 * Получаем ссылку на контроллер
	 *
	 * @param string $name имя контроллера
	 * @return Controller
	 */
	public static function &getController($name){
		if(!is_bool($obj=import('controller.'.$name,true,true))){
			return $obj;
		}
		$obj=import('controller.error',true);
		return $obj;
	}
	
	/**
	 * проверка на существование языка
	 *
	 * @param string $lang название языка
	 * @return boolean
	 */
	public static function checkLang($lang){
		if(!isset(self::$vars['allowed_lang'])){
			self::$vars['allow_lang']=explode(', ',Config::_('allow_lang'));
		}
		if(in_array($lang,self::$vars['allow_lang'])){
            global $core_mode;
            if($core_mode=='static'){
                import('core.db.mysql');
                import('core.model');
            }
		    return import('model.lang',true)->getId($lang);
		}
		return false;
	}
	/**
	 * Меняем текущий язык
	 *
	 * @param string $lang
	 * @return boolean
	 */
	public static function setLang($lang=false){
	    $id=null;
		if($lang!==false && !$id=self::checkLang($lang))return false;
		if($lang && Vars::check(self::LANG) && $lang==Vars::_(self::LANG))return true;
		if($lang===false){
			if($lang=Session::_(self::LANG)==null){
				$lang=Config::_('default_lang');
				$id=self::checkLang($lang);
				Session::_(self::LANG,$lang);
				Session::_(self::LANG_ID,$id);
			}else{
				$lang=Session::_(self::LANG);
				if(is_numeric(Session::_(self::LANG_ID))){
				    $id=Session::_(self::LANG_ID);
				}else{
				    $id=self::checkLang($lang);
				    Session::_(self::LANG_ID,$id);
				}
			}		
		}else{
		    if(!$id)$id=self::checkLang($lang);
			Session::_(self::LANG,$lang);
			Session::_(self::LANG_ID,$id);
		}
		Vars::_(self::LANG, $lang);
		Vars::_(self::LANG_ID, $id);
		L('Переключаем язык на '.$lang);
		return true;
	}
	/**
	 * Редирект страници
	 *
	 * @param string $url адресс для перехода
	 * @param array $message сообщения которые надо напечатать после редиректа
	 */
	public static function redirect($url,$message){
		if($message)self::messages($message);
		self::pastService();
		coreExit(false);
        if(Vars::_(Router::VIEW_TYPE) != 'json') {
            header("location: ".$url);
        } else {
            global $controller;
            $controller->view->set('message',$message);
            $controller->view->set('redirect',$url);
            $controller->view->show();
        }
		exit();
	}
	/**
	 * Возвращаем список одноразовых сообщений (или добавляем ещё одно)
	 *
	 * @param string $message новое сообщение
	 * @return array
	 */
	public static function messages($message=false){
		if(!isset($_SESSION[self::MESSAGES])){
			
			if(!$message)return false;
			$_SESSION[self::MESSAGES]=array();
		}
		if($message){
			$_SESSION[self::MESSAGES][]=$message;
			return $_SESSION[self::MESSAGES];
		}
		$messages=$_SESSION[self::MESSAGES];
		unset($_SESSION[self::MESSAGES]);
		return $messages;
	}
	/**
	 * Возвращаем список одноразовых ошибок формы
	 *
	 * @return array список
	 */
	public static function getFormErrors(){
		if(!isset($_SESSION[self::FORM_ERRORS]))return false;
		$form_errors=$_SESSION[self::FORM_ERRORS];
		//очищаем список
		unset($_SESSION[self::FORM_ERRORS]);
		return $form_errors;
	}
	/**
	 * Добавляем ошибку в стек ошибок
	 *
	 * @param array $errors список ошибок
	 */
	public static function setFormErrors($errors){
		if(!isset($_SESSION[self::FORM_ERRORS]))$_SESSION[self::FORM_ERRORS]=array();
		$_SESSION[self::FORM_ERRORS]=array_merge($_SESSION[self::FORM_ERRORS], $errors);
	}
	/**
	 * Запоминаем реферер для переброса
	 *
	 */
	public static function saveReferer(){
		if($referer=Request::getString(self::REFERER)){
			$_SESSION[self::REFERER]=base64_decode($referer);
		}
	}
	/**
	 * Сохраняем все данные запроса
	 *
	 */
	public static function saveRequest(){
		$_SESSION[self::LAST_REQUEST]=Request::get();
	}
	/**
	 * Очищаем данные формы
	 *
	 */
	public static function eraseRequest(){
		unset($_SESSION[self::LAST_REQUEST]);
	}
	/**
	 * Возвращаем рефер
	 *
	 * @return string
	 */
	public static function getReferer($noSession=false){
		if(isset($_SESSION[self::REFERER]) && !$noSession){
			$referer=$_SESSION[self::REFERER];
			unset($_SESSION[self::REFERER]);
		}else{
			$referer=isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:"/";
		}
		return $referer;
	}
	/**
	 * Сервисные операции перед запуском всего
	 *
	 */
	public static function preService(){
		global $db;
		//загружаемый базовый язык
		T::load('base');
		//сохраняем пропущенные тексты
		T::$debug_mode=T::LOG_DEBUG;
		if(isset($db) && isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']) && $_SESSION['user_id']){
			$db->query('SET @current_user = ' . $_SESSION['user_id']);
		}

		Vars::_(self::REFERER,base64_encode(self::getReferer()));
		Vars::_(self::FORM_ERRORS,self::getFormErrors());
		Vars::_(self::LAST_REQUEST,isset($_SESSION[self::LAST_REQUEST])?$_SESSION[self::LAST_REQUEST]:array());
	}
	/**
	 * Сервисные операции после запуском всего
	 *
	 */
	public static function pastService(){
		//записываем пропущенные переводы
		T::buildLostTranslate();
	}
	/**
	 * Проверяем залогиненость пользователя
	 *
	 * @return boolean
	 */
	public static function isLogin(){
		if(isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']) && $_SESSION['user_id']){
			return true;
		}
		return false;
	}
	/**
	 * Возвращаем теекущего пользователя
	 *
	 * @return int
	 */
	public static function user(){
		if(self::isLogin())return $_SESSION['user_id'];
		return false;
	}
	
	/**
	 * Возвращаем теекущего магазина
	 *
	 * @return int
	 */
	public static function shop(){
		return Vars::_(Router::SHOP_ID);
	}
	/**
	 * Выкидывает на главную если пользователь не залогинен
	 *
	 */
	public static function mustLogin(){
		if(!self::isLogin()){
            if(Vars::_(Router::VIEW_TYPE)=='json') {
                global $views;
                $views->setAll(array('error' => T::_('Must_login')));
            } else {
                self::redirect('/main',T::_('Must_login'));
            }
            return false;
		}
        return true;
	}
	/**
	 * Преобразовываем json или из строки в обект или наоборот
	 *
	 * @param mixed $data JSON или объект
	 * @return mixed объект или JSON
	 */
	public static function json($data){
	    if(is_string($data))$param=json_decode($data);
	    else $param=json_encode($data);
	    //обнуляем ошибку
	    self::set(self::LAST_ERROR,false);
        if(json_last_error()){
    		switch(json_last_error())
    		{
    		    case JSON_ERROR_DEPTH:
    		        $error='JSON Maximum stack depth exceeded';
    		        break;
    		    case JSON_ERROR_CTRL_CHAR:
    		        $error='JSON Unexpected control character found';
    		        break;
    		    case JSON_ERROR_SYNTAX:
    		        $error='JSON Syntax error, malformed JSON';
    		        break;
    		    default:
    		        $error='JSON Uincom error';
    		        break;
    		}
    		//зфписываем ошибку
    		self::set(self::LAST_ERROR,$error);
    		new CoreExeption($error,E_WARNING,__FILE__,__LINE__,array('data'=>$data));
    		return false;
		}
		return $param;
	}
    public static function isJSON(){
        return Vars::_(Router::VIEW_TYPE) == 'json';
    }
	/**
	 * Показываем последнюю ошибку ядра
	 *
	 * @return string текст ошибки
	 */
	public static function lastError(){
	    if($lastError=self::get(self::LAST_ERROR)){
	        //обнуляем ошибку
	        self::set(self::LAST_ERROR,false);
	        return $lastError;
	    }
	    return false;
	}
	public static function setAccess($name='access'){
	    if($access=Request::getVar($name,false)){
	        $bin='1';
	        $bin.=isset($access['other'])?"1":"0";
	        $bin.=isset($access['friends'])?"1":"0";
	        $bin.=isset($access['users'])?"1":"0";
	        $bin.=isset($access['all'])?"1":"0";
	        return strtoupper((dechex(bindec($bin)-16)));
	    }return 0;
	}
	public static function clearLastRequest(){
	    //очищаем данные предыдущих запросов
	    if(isset($_SESSION[self::LAST_REQUEST]))unset($_SESSION[self::LAST_REQUEST]);
	}
	public static function date($date=null){
	    return date('Y-m-d H:i:s',$date?$date:time());
	}
	public static function lang(){
	    return Vars::_(Core::LANG_ID);
	}
}